package com.yanqu.file;

import cn.thinkingdata.tga.javasdk.inter.Consumer;
import com.alibaba.fastjson.JSON;
import net.sf.json.JSONException;

import java.io.File;
import java.io.FileNotFoundException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

public class LoggerConsumer implements Consumer {


    private final static String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";

    private final String fileName;
    private final String lockFileName;
    private final int bufferSize;
    private final int fileSize;
    private Timer autoFlushTimer;

    private final StringBuffer messageBuffer = new StringBuffer();
    private final ThreadLocal<SimpleDateFormat> df;

    private LoggerFileWriter loggerWriter;

    /**
     * 创建指定配置信息的 LoggerConsumer
     *
     * @param config LoggerConsumer.Config instance.
     */
    public LoggerConsumer(final FileConfig config) {
        if (config.logDirectory == null || config.logDirectory.length() == 0) {
            throw new RuntimeException("指定的目录路径不能为空！");
        }
        File dir = new File(config.logDirectory);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        if (!dir.isDirectory()) {
            throw new RuntimeException("指定的路径必须是个目录：" + config.logDirectory);
        }
        String fileNamePrefix = config.fileNamePrefix == null ? config.logDirectory + File.separator : config.logDirectory + File.separator + config.fileNamePrefix + ".";
        this.fileName = fileNamePrefix + "log.";
        this.fileSize = config.fileSize;
        this.lockFileName = config.lockFileName;
        this.bufferSize = config.bufferSize;

        final String dataFormat = config.rotateMode == RotateMode.HOURLY ? "yyyy-MM-dd-HH" : "yyyy-MM-dd";
        df = new ThreadLocal<SimpleDateFormat>() {
            @Override
            protected SimpleDateFormat initialValue() {
                return new SimpleDateFormat(dataFormat);
            }
        };

        if (config.autoFlush) {
            if (config.interval <= 0) {
                config.interval = 3;
            }
            autoFlushTimer = new Timer();
            autoFlushTimer.schedule(new TimerTask() {
                public void run() {
                    flush();
                }
            }, 1000, config.interval * 1000);
        }
    }

    /**
     * 创建指定日志存放目录的 LoggerConsumer. 单个日志文件大小默认为 1G.
     *
     * @param logDirectory 日志存放目录
     */
    public LoggerConsumer(final String logDirectory) {
        this(new FileConfig(logDirectory));
    }

    /**
     * 创建指定日志存放目录的 LoggerConsumer, 并指定单个日志文件大小.
     *
     * @param logDirectory 日志目录
     * @param fileSize     单个日志文件大小限制，单位 MB
     */
    public LoggerConsumer(final String logDirectory, int fileSize) {
        this(new FileConfig(logDirectory, fileSize));
    }


    @Override
    public synchronized void add(Map<String, Object> message) {
        try {
            messageBuffer.append(JSON.toJSONStringWithDateFormat(message, DEFAULT_DATE_FORMAT));
            messageBuffer.append("\n");
        } catch (JSONException e) {
            throw new RuntimeException("Failed to add data", e);
        }

        if (messageBuffer.length() >= bufferSize) {
            this.flush();
        }
    }

    public synchronized void add(StringBuffer message) {
        messageBuffer.append(message);
        if (messageBuffer.length() >= bufferSize) {
            this.flush();
        }
    }

    public synchronized void add(StringBuilder message) {
        messageBuffer.append(message);
        if (messageBuffer.length() >= bufferSize) {
            this.flush();
        }
    }

    @Override
    public synchronized void flush() {
        if (messageBuffer.length() == 0) {
            return;
        }

        String fileName = getFileName();
        if (loggerWriter != null && !loggerWriter.getFileName().equals(fileName)) {
            LoggerFileWriter.removeInstance(loggerWriter);
            loggerWriter = null;
        }

        if (loggerWriter == null) {
            try {
                loggerWriter = LoggerFileWriter.getInstance(fileName, lockFileName);
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            }
        }

        if (loggerWriter.write(messageBuffer)) {
            messageBuffer.setLength(0);
        }
    }

    private String getFileName() {
        String resultPrefix = fileName + df.get().format(new Date()) + "_";
        int count = 0;
        String result = resultPrefix + count;
        if (fileSize > 0) {
            File target = new File(result);
            while (target.exists()) {
                if ((target.length() / (1024 * 1024)) < fileSize) {
                    break;
                }
                result = resultPrefix + (++count);
                target = new File(result);
            }
        }
        return result;
    }

    @Override
    public synchronized void close() {
        this.flush();
        if (loggerWriter != null) {
            LoggerFileWriter.removeInstance(loggerWriter);
            loggerWriter = null;
        }
        if (autoFlushTimer != null) {
            autoFlushTimer.cancel();
        }
    }


}